<template>
  <!-- 添加任务 -->
  <div>
    <button @click="addTask">添加任务</button>
  </div>
  <!-- 甘特图 -->
  <div class="gantt-container" ref="ganttContainer"></div>
  <div>
    <!-- 状态选择框 -->
    <el-dialog
      :modal="false"
      :show-close="false"
      v-model="statusShow"
      :style="{
        margin: '0',
        position: 'absolute',
        width: statusWidth,
        height: '200px',
        top: statusTop,
        left: statusLeft,
        padding: '0px',
        border: '1px solid #eee',
        boxShadow: '0 0 16px #00000014',
        borderRadius: '2px',
      }"
    >
      <div>
        <div class="dialog-menu-item" @click="changeStatus('未开始')">
          <span style="background-color: rgb(86, 171, 251)">未开始</span>
        </div>
        <div class="dialog-menu-item" @click="changeStatus('进行中')">
          <span style="background-color: rgb(246, 198, 89)">进行中</span>
        </div>
        <div class="dialog-menu-item" @click="changeStatus('已完成')">
          <span style="background-color: rgb(115, 216, 151)">已完成</span>
        </div>
        <div class="dialog-menu-item" @click="changeStatus('未完成')">
          <span style="background-color: rgb(255, 117, 117)">未完成</span>
        </div>
      </div>
    </el-dialog>

    <!-- 里程碑选择框 -->
    <el-dialog
      :modal="false"
      :show-close="false"
      v-model="lichenbeiShow"
      :style="{
        margin: '0',
        position: 'absolute',
        width: lichenbeiWidth,
        height: '120px',
        top: lichenbeiTop,
        left: lichenbeiLeft,
        padding: '0px',
        border: '1px solid #eee',
        boxShadow: '0 0 16px #00000014',
        borderRadius: '2px',
      }"
    >
      <div>
        <div class="dialog-menu-item" @click="changeLichenbei(1)">
          <span style="background-color: rgb(255, 117, 117)">是</span>
        </div>
        <div class="dialog-menu-item" @click="changeLichenbei(0)">
          <span style="background-color: rgb(170, 170, 170)">否</span>
        </div>
      </div>
    </el-dialog>

    <!-- 任务日期选择 -->
    <el-date-picker
      @change="onDateChange"
      ref="datePickerRef"
      v-model="datePickerValue"
      type="date"
      placeholder="选择日期"
      :style="{
        position: 'fixed',
        left: datePickerLeft,
        top: datePickerTop,
        width: '0px',
        zIndex: -3000,
      }"
      :teleported="true"
    ></el-date-picker>

    <!-- 更多弹窗 -->
    <el-popover
      v-model:visible="popoverVisible"
      :width="160"
      trigger="manual"
      :virtual-ref="virtualRef"
      virtual-triggering
      popper-class="no-padding-popover"
    >
      <div class="gantt-popover-content">
        <div class="gantt-popover-item">复制编号</div>
        <div class="gantt-popover-item">日期变更</div>
        <div class="gantt-popover-item">设置标签</div>
        <div class="gantt-popover-item">删除</div>
      </div>
    </el-popover>

    <!-- 任务类型 -->
    <el-popover
      v-model:visible="taskTypeVisible"
      :width="160"
      trigger="manual"
      :virtual-ref="taskTypeRef"
      virtual-triggering
      popper-class="no-padding-popover"
    >
      <div id="change-task-type" class="gantt-popover-content">
        <div class="gantt-popover-item" @click="changeTaskType(4)">
          <svg style="width: 14px; height: 14px; fill: rgb(115, 216, 151)">
            <use href="#icon-worktile-task" />
          </svg>
          任务
        </div>
        <div class="gantt-popover-item" @click="changeTaskType(3)">
          <svg style="width: 14px; height: 14px; fill: rgb(48, 209, 252)">
            <use href="#icon-worktile-user" />
          </svg>
          模块
        </div>
      </div>
    </el-popover>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick, unref } from "vue";
import { ElMessage } from "element-plus";
import { ElProgress } from "element-plus";
import { gantt } from "dhtmlx-gantt";
import "dhtmlx-gantt/codebase/dhtmlxgantt.css";

const ganttContainer = ref(null);
const currentTaskId = ref(""); // 当前任务id

// 任务开始结束日期弹窗
const datePickerType = ref(""); // 日期选择器类型
const datePickerValue = ref("");
const datePickerLeft = ref("0px");
const datePickerTop = ref("0px");
const datePickerRef = ref(null);

// 更多菜单弹窗
const popoverRef = ref();
const popoverLeft = ref("0px");
const popoverTop = ref("0px");
const popoverVisible = ref(false);

// 里程碑弹窗
const lichenbeiShow = ref(false);
const lichenbeiWidth = ref("0px");
const lichenbeiLeft = ref("0px");
const lichenbeiTop = ref("0px");

// 状态弹窗
const statusShow = ref(false);
const statusWidth = ref("0px");
const statusLeft = ref("0px");
const statusTop = ref("0px");

const virtualRef = ref({
  getBoundingClientRect: () => ({
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  }),
  contextElement: null,
});
const taskTypeRef = ref({
  getBoundingClientRect: () => ({
    width: 0,
    height: 0,
    top: 0,
    left: 0,
  }),
  contextElement: null,
});

// 任务列表
const listData = {
  // 任务数据
  data: [
    {
      id: 1,
      text: "子系统01", // 标题
      lichenbei: 1, // 里程碑 1是 0否
      status: "未开始", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-01", // 开始时间
      end_date: "2025-06-05", // 结束时间
      progress: 1, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 1, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 0,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 2,
      text: "需求分析",
      lichenbei: 0, // 里程碑 1是 0否
      status: "进行中",
      leader: "张三",
      start_date: "2025-06-08",
      end_date: "2025-06-12",
      progress: 0, // 进度 0未开始-1已完成
      chanchuwu: true,
      taskType: 2, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 1,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 3,
      text: "UI设计",
      lichenbei: 1, // 里程碑 1是 0否
      status: "已完成",
      leader: "张三",
      start_date: "2025-06-28",
      end_date: "2025-07-04",
      progress: 0.2, // 进度 0未开始-1已完成
      chanchuwu: true,
      taskType: 2, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 1,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 4,
      text: "项目实施", // 标题
      lichenbei: 0, // 里程碑 1是 0否
      status: "进行中", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-02", // 开始时间
      end_date: "2025-06-07", // 结束时间
      progress: 0.6, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 1, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 0,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 5,
      text: "项目实施项目实施项项目实施项目实施项项目实施项目实施项", // 标题
      lichenbei: 1, // 里程碑 1是 0否
      status: "未完成", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-04", // 开始时间
      end_date: "2025-06-08", // 结束时间
      progress: 0.6, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 2, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 4,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 6,
      text: "甘特图模块功能开发及自测功甘特图模块功能开发及自测功", // 标题
      lichenbei: 1, // 里程碑 1是 0否
      status: "未完成", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-04", // 开始时间
      end_date: "2025-06-08", // 结束时间
      progress: 0.6, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 3, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 2,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 7,
      text: "开发任务开发任务", // 标题
      lichenbei: 1, // 里程碑 1是 0否
      status: "未完成", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-04", // 开始时间
      end_date: "2025-06-08", // 结束时间
      progress: 0.6, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 4, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 6,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
    {
      id: 8,
      text: "开发任务", // 标题
      lichenbei: 1, // 里程碑 1是 0否
      status: "未完成", // 状态
      leader: "张三", // 负责人
      start_date: "2025-06-04", // 开始时间
      end_date: "2025-06-08", // 结束时间
      progress: 0.6, // 进度 0未开始-1已完成
      chanchuwu: true, // 产出物
      taskType: 4, // 类型 1:系统 2:需求 3:模块 4:任务
      parent: 6,
      operate: 3, // 操作 1:新增 2:编辑 3:预览
    },
  ],
  // 关系线
  links: [
    // { id: 1, source: 1, target: 2, type: "0" },
    // { id: 2, source: 2, target: 3, type: "0" },
  ],
};
// 任务标题操作变量
const taskTitleEdit = ref(""); // 标题名称（新增任务、编辑标题）
const taskTypeVisible = ref(false); // 任务类型弹窗
const taskIdAdd = ref(""); // 新增任务时记录任务id用于后面调编辑接口

// 初始化甘特图
const initGantt = async () => {
  await nextTick();
  // 配置甘特图
  // 1. 时间刻度配置（控制甘特图顶部和底部的时间标尺显示方式。）
  gantt.config.scale_unit = "week"; // 主刻度单位："day" | "week" | "month" | "year"
  gantt.config.step = 1; // 主刻度步长
  gantt.config.date_scale = "%Y年%n月"; // 主刻度日期格式
  gantt.config.subscales = [{ unit: "day", step: 1, date: "%j" }]; // 副刻度格式
  gantt.config.min_column_width = 25; // 最小列宽(像素)
  gantt.config.scale_height = 43; // 主刻度高度(像素)

  // 2. 任务视图配置（控制任务的显示方式。）
  gantt.config.row_height = 44; // 每行高度(像素)
  gantt.config.bar_height = 20; // 任务条实际高度(像素)
  gantt.config.drag_resize = true; // 允许拖拽调整任务条大小
  gantt.config.drag_move = true; // 允许拖拽移动任务条
  gantt.config.show_progress = true; // 显示任务完成进度条
  gantt.config.open_tree_initially = true; // 初始化时展开树形结构
  // gantt.config.autosize = "y"; // 自动调整高度以适应内容

  // 3. 日期格式配置（控制日期的显示和解析格式。）
  gantt.config.date_format = "%Y-%m-%d"; // 内部日期存储格式
  gantt.config.xml_date = "%Y-%m-%d"; // 与服务器交换数据的格式
  // gantt.templates.task_date = function (date) {
  //   // 任务条上的日期显示格式
  //   return gantt.date.date_to_str("%m-%d")(date);
  // };
  gantt.config.autofit = true;
  // gantt.config.readonly = true; // 禁用所有交互（选择、拖动等）

  // 4. 列配置（控制甘特图的列显示方式。）
  gantt.config.columns = [
    // 序号
    {
      name: "serial",
      label: "序号",
      width: 50,
      template: function (task) {
        // 0. 一级目录不显示序号
        if (task.parent === 0) return "";

        // 1. 找到当前任务所属的一级目录
        let topLevelParentId = task.parent;
        let currentTask = gantt.getTask(topLevelParentId);
        while (currentTask.parent !== 0) {
          topLevelParentId = currentTask.parent;
          currentTask = gantt.getTask(topLevelParentId);
        }

        // 2. 获取该一级目录下的所有非一级目录任务
        let nonRootTasksUnderTopLevel = [];
        gantt.eachTask(function (t) {
          // 一级直接跳过
          if (t.parent == 0) return;
          let item = t;
          while (item.parent != 0) {
            if (item.parent == topLevelParentId) {
              nonRootTasksUnderTopLevel.push(t);
              break;
            }
            item = gantt.getTask(item.parent);
          }
        });
        // 3. 获取当前任务在非一级目录任务中的索引
        let index = nonRootTasksUnderTopLevel.indexOf(task);
        if (index !== -1) {
          return `<div style="text-align:center;color:#666">${index + 1}</div>`;
        }
        return "";
      },
    },
    // 任务标题
    {
      name: "text",
      label: "标题",
      tree: true,
      width: 300,
      template: (val) => {
        // operate 1:新增 2:编辑 3:预览
        if (val.operate == 1) {
          return `
          <div id="add-task-div" style="background-color:#fff;position:absolute;top:0;left:50px;width:300px;height:42px;box-shadow:0px 4px 16px 0px rgba(0,0,0,0.12);z-index:1000;border-radius:2px;overflow:hidden;display:flex;align-items:center;">
            <input type="text" value="${
              taskTitleEdit.value
            }" style="width:100%;height:100%;border:none;outline:none;" oninput="window.handleInputChange(event)" />
            <div grow-open-task-type="${
              val.id
            }" pointer-events="none" data-id="openTaskType" style="display:flex;align-items:center;margin-right:6px;gap:4px;cursor:pointer;height:100%">
              ${
                val.taskType == 3
                  ? `<svg pointer-events="none" style="width:14px;height:14px;fill:rgb(48, 209, 252);"><use href="#icon-worktile-user" /></svg>`
                  : val.taskType == 4
                  ? `<svg pointer-events="none" style="width:14px;height:14px;fill:rgb(115, 216, 151);"><use href="#icon-worktile-task" /></svg>`
                  : ``
              }
                <svg pointer-events="none" style="width:12px;height:12px;fill:rgba(170, 170, 170, 1);"><use href="#icon-public-DownOutlined" /></svg>
            </div>
          </div>`;
        } else if (val.operate == 2) {
          return `<div style="background-color:#fff;position:absolute;top:0;left:50px;width:300px;height:42px;box-shadow:0px 4px 16px 0px rgba(0,0,0,0.12);z-index:1000;border-radius:2px;overflow:hidden;">
            <input type="text" value="${taskTitleEdit.value}" style="width:100%;height:100%;border:none;outline:none;" oninput="window.handleInputChange(event)"  onblur="window.handleInputBlur(event, '${val.id}')"/>
          </div>`;
        } else {
          return `
          <div class="task-cell">
            <div style="display:flex;align-items:center;margin-right:4px;">${
              val.taskType == 1
                ? `<svg style="width:14px;height:14px;fill:rgb(255, 135, 123);"><use href="#icon-worktile-epic" /></svg>`
                : val.taskType == 2
                ? `<svg style="width:14px;height:14px;fill:rgb(145, 145, 249);"><use href="#icon-worktile-feature" /></svg>`
                : val.taskType == 3
                ? `<svg style="width:14px;height:14px;fill:rgb(48, 209, 252);"><use href="#icon-worktile-user" /></svg>`
                : val.taskType == 4
                ? `<svg style="width:14px;height:14px;fill:rgb(115, 216, 151);"><use href="#icon-worktile-task" /></svg>`
                : ""
            }</div>
            <div data-id="text" style="flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">
            ${val.text}
            </div>
            <div class="task-cell-right">
              ${
                val.taskType != 4
                  ? `<div class="gantt-addTask" data-id="addTask"><svg pointer-events="none" style="width:14px;height:14px;fill:rgba(170, 170, 170, 1);"><use href="#icon-line-PlusCircle" /></svg></div>`
                  : ""
              }
              <div class="gantt-addTask" data-id="editTask">
                <svg pointer-events="none" style="width:14px;height:14px;fill:rgba(170, 170, 170, 1);"><use href="#icon-line-Sign" /></svg>
              </div>
              <div class="gantt-addTask" data-id="openMore">
                <svg pointer-events="none" style="width:14px;height:14px;fill:rgba(170, 170, 170, 1);"><use href="#icon-public-MoreFilled-vertical" /></svg>
              </div>
            </div>
          </div>`;
        }
      },
    },
    {
      name: "lichenbei",
      label: "里程碑",
      align: "center",
      width: 70,
      template: (val) => {
        return `
        <div class="lichenbei-cell" grow-lichenbei="${
          val.id
        }" data-id="lichenbei">
          <span data-id="lichenbei" class="gantt-lichenbei" style="background-color:${
            val.lichenbei == 1 ? "rgb(255, 117, 117)" : "rgb(170, 170, 170)"
          }">${val.lichenbei == 1 ? "是" : "否"}</span>
          <svg class="lichenbei-cell-right" pointer-events="none"><use href="#icon-public-DownOutlined" /></svg>
        </div>`;
      },
    },
    {
      name: "status",
      label: "状态",
      align: "center",
      width: 90,
      template: (val) => {
        return `
        <div class="status-cell" grow-status="${val.id}" data-id="status">
          <span data-id="status" class="gantt-status" style="background-color:
          ${
            val.status == "未开始"
              ? "rgb(86, 171, 251)"
              : val.status == "进行中"
              ? "rgb(246, 198, 89)"
              : val.status == "已完成"
              ? "rgb(115, 216, 151)"
              : "rgb(255, 117, 117)"
          }" >${val.status}</span>
          <svg class="status-cell-right" pointer-events="none"><use href="#icon-public-DownOutlined" /></svg>
        </div>`;
      },
    },
    {
      name: "leader",
      label: "负责人",
      align: "center",
      width: 70,
      template: (val) => {
        return `
        <div class="leader-cell" data-id="leader">
          <span data-id="leader">${val.leader}</span>
          <svg class="leader-cell-right" pointer-events="none"><use href="#icon-line-AddPerson" /></svg>
        </div>`;
      },
    },
    {
      name: "start_date",
      label: "开始时间",
      align: "center",
      width: 120,
      template: (val) => {
        return `
        <div class="start-end-cell" data-id="start_date">
        ${
          val.start_date
            ? `<span data-id="start_date">${gantt.date.date_to_str("%Y-%m-%d")(
                val.start_date
              )}</span>`
            : ""
        }
          <svg class="start-end-cell-right" pointer-events="none"><use href="#icon-line-Timing" /></svg>
        </div>`;
      },
    },
    {
      name: "end_date",
      label: "结束时间",
      align: "center",
      width: 120,
      template: (val) => {
        return `
        <div class="start-end-cell" data-id="end_date">
         ${
           val.end_date
             ? `<span data-id="end_date">${gantt.date.date_to_str("%Y-%m-%d")(
                 val.end_date
               )}</span>`
             : ""
         }
          <svg class="start-end-cell-right" pointer-events="none"><use href="#icon-line-Timing" /></svg>
        </div>`;
      },
    },
    {
      name: "progress",
      label: "任务进度",
      align: "center",
      width: 100,
      template: (task) => {
        const progressValue = Math.round(task.progress * 100);
        // 模板字符串中直接使用 Element Plus 组件不会自动渲染，
        // 现在使用原生的 HTML 和 CSS 来实现进度条效果，这样可以确保在甘特图中正确显示。
        return `
          <div class="progress-cell">
            <div class="progress-cell-bg">
              <div class="progress-cell-value" style="width:${progressValue}%;background:${
          progressValue == 100 ? "#67c23a" : "#409eff"
        }"></div>
            </div>
            <div style="font-size:11px;color:#606266;margin-left:4px;">${progressValue}%</div>
          </div>
        `;
      },
    },
    {
      name: "chanchuwu",
      label: "产出物",
      align: "center",
      width: 70,
      template: (task) => {
        return `<span data-id="chanchuwu" style="color:#007bff;cursor:pointer;">查看</span>`;
      },
    },
  ];

  gantt.templates.grid_open = (task) => {
    return task.$open
      ? `<div class="my-collapse-icon" data-task-id="${task.id}" style="display:flex;align-items:center;margin-right:2px;"><svg style="fill:rgba(170, 170, 170, 1)" width="13" height="13" pointer-events="none"><use href="#icon-public-DownOutlined"/></svg></div>`
      : `<div class="my-expand-icon" data-task-id="${task.id}" style="display:flex;align-items:center;margin-right:2px;"><svg style="fill:rgba(170, 170, 170, 1)" width="13" height="13" pointer-events="none"><use href="#icon-public-RightOutlined"/></svg></div>
      `;
  };
  // 自定义展开/折叠图标模板
  gantt.attachEvent("onGanttReady", () => {
    // 绑定点击事件处理展开/折叠
    gantt.$container.addEventListener("click", (e) => {
      const target = e.target;
      if (
        target.classList.contains("my-expand-icon") ||
        target.classList.contains("my-collapse-icon")
      ) {
        const taskId = target.getAttribute("data-task-id");
        if (taskId) {
          const task = gantt.getTask(taskId);
          // 判断任务是否展开
          if (task.$open) {
            gantt.close(task.id);
          } else {
            gantt.open(task.id);
          }
          e.stopPropagation();
        }
      }
    });
  });

  // 初始化甘特图配置（初始化甘特图，并设置甘特图的容器）
  gantt.init(ganttContainer.value);
  // 设置甘特图数据（设置甘特图的配置和数据）
  gantt.parse(listData);

  // onTaskClick：点击任务时触发绑定事件（id：任务id，e：事件对象）
  gantt.attachEvent("onTaskClick", function (id, e) {
    // 点击了添加任务
    if (e.target.dataset.id === "addTask") {
      addTask(id);
      return false;
    }
    // 点击了编辑任务
    if (e.target.dataset.id === "editTask") {
      let task = gantt.getTask(id);
      taskTitleEdit.value = task.text;
      task.operate = 2; // 操作 1:新增 2:编辑 3:预览
      gantt.updateTask(task.id); // 更新任务
      // 聚焦到新增任务的输入框
      const taskRow = document.querySelector(
        `.gantt_row[data-task-id="${id}"]`
      );
      if (taskRow) {
        const input = taskRow.querySelector('input[type="text"]');
        input.focus();
      }
      return false;
    }
    // 点击了产出物
    if (e.target.dataset.id === "chanchuwu") {
      ElMessage.success("点击了产出物");
      return false;
    }
    // 点击了结束时间
    if (e.target.dataset.id === "end_date") {
      currentTaskId.value = id;
      datePickerType.value = "end_date";
      datePickerLeft.value = e.clientX + "px";
      datePickerTop.value = e.clientY + "px";
      // 直接弹出日期选择器
      nextTick(() => {
        datePickerRef.value.focus();
      });
      return false;
    }
    // 点击了开始时间
    if (e.target.dataset.id === "start_date") {
      currentTaskId.value = id;
      datePickerType.value = "start_date";
      datePickerLeft.value = e.clientX + "px";
      datePickerTop.value = e.clientY + "px";
      // 直接弹出日期选择器
      nextTick(() => {
        datePickerRef.value.focus();
      });

      return false;
    }
    // 点击了负责人
    if (e.target.dataset.id === "leader") {
      ElMessage.success("点击了负责人");
      return false;
    }
    // 点击了状态
    if (e.target.dataset.id === "status") {
      const taskElement = document.querySelector(`[grow-status='${id}']`);
      const taskElementRect = taskElement.getBoundingClientRect();
      currentTaskId.value = id; // 当前任务id
      statusTop.value = taskElementRect.bottom + 2 + "px";
      statusWidth.value = taskElementRect.width + "px";
      statusLeft.value = taskElementRect.left + "px";
      statusShow.value = true;
      return false;
    }
    // 点击了里程碑
    if (e.target.dataset.id === "lichenbei") {
      const taskElement = document.querySelector(`[grow-lichenbei='${id}']`);
      const taskElementRect = taskElement.getBoundingClientRect();
      currentTaskId.value = id; // 当前任务id
      lichenbeiTop.value = taskElementRect.bottom + 2 + "px";
      lichenbeiWidth.value = taskElementRect.width + "px";
      lichenbeiLeft.value = taskElementRect.left + "px";
      lichenbeiShow.value = true;
      return false;
    }
    // 点击了打开更多
    if (e.target.dataset.id === "openMore") {
      currentTaskId.value = id; // 当前任务id
      popoverLeft.value = e.clientX + "px";
      popoverTop.value = e.clientY + "px";
      console.log(popoverLeft.value, popoverTop.value);
      virtualRef.value.getBoundingClientRect = () => ({
        width: 0,
        height: 0,
        top: e.clientY,
        left: e.clientX,
      });
      popoverVisible.value = true;
      return false;
    }
    // 点击了打开任务类型
    if (e.target.dataset.id === "openTaskType") {
      currentTaskId.value = id; // 当前任务id
      const taskElement = document.querySelector(
        `[grow-open-task-type='${id}']`
      );
      const taskElementRect = taskElement.getBoundingClientRect();
      taskTypeRef.value.getBoundingClientRect = () => ({
        width: 0,
        height: 0,
        top: taskElementRect.bottom - 10,
        left: taskElementRect.left + 15,
      });
      taskTypeVisible.value = true;
      return false;
    }
    return true; // 返回false可阻止默认行为
  });
  // 阻止默认的双击行为（如打开任务编辑器）
  gantt.attachEvent("onTaskDblClick", function (id, e) {
    // 阻止默认的双击行为（如打开任务编辑器）
    return false;
  });
};

// 第一步. 添加任务/子任务
const addTask = (parentId) => {
  taskTitleEdit.value = ""; // 编辑任务标题输入框内容
  taskIdAdd.value = gantt.uid ? gantt.uid() : Date.now(); // 兼容旧版本的ID生成

  parentId && gantt.open(parentId);
  gantt.addTask({
    id: taskIdAdd.value,
    text: "新任务",
    start_date: "",
    end_date: "",
    progress: 0,
    status: "未开始",
    leader: "张三",
    lichenbei: 0,
    chanchuwu: false,
    parent: parentId ? parentId : 0,
    taskType: 4, // 类型 1:系统 2:需求 3:模块 4:任务
    operate: 1, // 操作 1:新增 2:编辑 3:预览
  });
  // 设置输入框焦点
  const taskRow = document.querySelector(
    `.gantt_row[data-task-id="${taskIdAdd.value}"]`
  );
  if (taskRow) {
    const input = taskRow.querySelector('input[type="text"]');
    input.focus();
  }
  // 新增任务时，创建窗口点击事件监听
  document.addEventListener("mousedown", addTaskTitle);
};
// 第二步. 新增任务时，创建窗口点击事件监听
const addTaskTitle = (event) => {
  const addTaskDiv = document.getElementById("add-task-div");
  if (!addTaskDiv) return;
  const changeTaskType = document.getElementById("change-task-type");
  // compareDocumentPosition()方法
  // 0  表示完全相等，即两个节点是同一个节点。
  // 2  A在B的前面,并且A和 B之间没有包含关系（不是祖先/后代）
  // 4  A在B的后面,并且A和 B之间没有包含关系（不是祖先/后代）
  // 10 A被B包含（A是B的后代）,并且A在B前面（A在文档流中排在 B 之前）
  // 20 表示后代或自身
  if (
    addTaskDiv === event.target ||
    [20, 0].includes(addTaskDiv.compareDocumentPosition(event.target)) ||
    [20, 0].includes(changeTaskType.compareDocumentPosition(event.target))
  ) {
    console.log("点击发生在目标div内部");
  } else {
    console.log("点击发生在目标div外部");
    let task = gantt.getTask(taskIdAdd.value);
    // 新增任务时，没有输入任务标题放弃新增执行删除任务
    if (!!!taskTitleEdit.value.trim()) {
      gantt.deleteTask(task.id);
    } else {
      task.text = taskTitleEdit.value;
      task.operate = 3; // 操作 1:新增 2:编辑 3:预览
      gantt.updateTask(task.id);
    }
  }
};

// 修改=》状态
const changeStatus = (status) => {
  statusShow.value = false;
  let task = gantt.getTask(currentTaskId.value);
  task.status = status;
  gantt.updateTask(task.id); // 更新任务
};
// 修改=》任务类型
const changeTaskType = (type) => {
  taskTypeVisible.value = false;
  let task = gantt.getTask(currentTaskId.value);
  task.taskType = type;
  task.text = taskTitleEdit.value;
  gantt.updateTask(task.id); // 更新任务
};
// 修改=》里程碑
const changeLichenbei = (lichenbei) => {
  lichenbeiShow.value = false;
  let task = gantt.getTask(currentTaskId.value);
  task.lichenbei = lichenbei;
  gantt.updateTask(task.id); // 更新任务
};
// 修改=》日期
const onDateChange = (date) => {
  let task = gantt.getTask(currentTaskId.value);
  if (datePickerType.value === "start_date") {
    task.start_date = date;
  } else if (datePickerType.value === "end_date") {
    task.end_date = date;
  }
  gantt.updateTask(task.id); // 更新任务
};

// 监听任务标题输入框输入文本事件
window.handleInputChange = (event) => {
  taskTitleEdit.value = event.target.value;
};
// 编辑任务时，监听是否输入框失去焦点
window.handleInputBlur = (event, id) => {
  let task = gantt.getTask(id);
  // 没有值则不保存，直接展示老数据
  if (!!event.target.value.trim()) {
    task.text = event.target.value;
  }
  task.operate = 3;
  gantt.updateTask(task.id); // 更新任务
};

// 首次挂载到DOM后初始化甘特图
onMounted(() => {
  // 初始化甘特图
  initGantt();
});

// 组件实例被卸载时onBeforeUnmount会在销毁甘特图
onBeforeUnmount(() => {
  try {
    // 移除所有事件监听器
    gantt.detachAllEvents();

    // 释放内存
    gantt.clearAll();
  } catch (error) {}
});
</script>

<style scoped lang="scss">
/* 甘特图容器 */
.gantt-container {
  height: calc(100vh - 150px);
}
/*
每个单元格边框 border
鼠标悬浮背景色 hover
gantt_grid_data 左侧表格整个对象class
gantt_row 表格每一行
gantt_cell 表格每一个单元格
*/
::v-deep .gantt_grid_data {
  // 表格行
  .gantt_row {
    &:hover {
      background-color: #fafafa;
    }
    &.gantt_selected {
      background-color: #fff !important;
    }
  }
  // 表格单元格
  .gantt_cell {
    border-right: 1px solid rgba(242, 242, 242, 1) !important;
    padding: 0px;
  }
  // 收缩列样式（任务标题）
  .gantt_cell_tree {
    padding: 0 6px;
    .gantt_tree_content {
      flex-grow: 1;
      // 任务标题右侧操作按钮
      .gantt-addTask {
        border-radius: 4px;
        height: 30px;
        width: 30px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        &:hover {
          background-color: #6698ff1a !important;
          svg {
            fill: rgb(86, 171, 251) !important;
          }
        }
      }
    }
  }
}
/*
gantt_task_bg 右侧任务进度板块
gantt_task_row 表格每一行
 */
::v-deep .gantt_task_bg {
  .gantt_task_row {
    background-color: #fff !important;
  }
}

// 状态和里程碑下拉框选项样式
.dialog-menu-item {
  &:hover {
    background-color: #f5f5f5;
  }
  padding: 9px 10px;
  cursor: pointer;
  span {
    color: #fff;
    border-radius: 20px;
    padding: 6px 12px;
    font-size: 12px;
    line-height: 1;
    display: inline-block;
    vertical-align: middle;
  }
}

// 更多弹窗/任务类型样式
.gantt-popover-content {
  .gantt-popover-item {
    padding: 10px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    &:hover {
      background-color: #f0f2f5;
    }
  }
}

// 任务
::v-deep .task-cell {
  // cursor: pointer;
  display: flex;
  align-items: center;
  height: 100%;
  justify-content: space-between;
  .task-cell-right {
    display: none;
    align-items: center;
    gap: 2px;
  }
  &:hover .task-cell-right {
    display: flex;
  }
}
// 里程碑
::v-deep .lichenbei-cell {
  padding: 0px 10px;
  cursor: pointer;
  display: flex;
  align-items: center;
  height: 100%;
  justify-content: space-between;
  .gantt-lichenbei {
    color: #fff;
    border-radius: 20px;
    padding: 5px 10px;
    font-size: 11px;
    line-height: 1;
    display: inline-block;
  }
  .lichenbei-cell-right {
    width: 12px;
    height: 12px;
    fill: rgba(170, 170, 170, 1);
    display: none;
  }
  &:hover {
    background-color: #6698ff1a;
    .lichenbei-cell-right {
      display: block;
    }
  }
}
// 状态
::v-deep .status-cell {
  padding: 0px 10px;
  cursor: pointer;
  display: flex;
  align-items: center;
  height: 100%;
  justify-content: space-between;
  .gantt-status {
    color: #fff;
    border-radius: 20px;
    padding: 5px 10px;
    font-size: 11px;
    line-height: 1;
    display: inline-block;
  }
  .status-cell-right {
    display: none;
    width: 12px;
    height: 12px;
    fill: rgba(170, 170, 170, 1);
  }
  &:hover {
    background-color: #6698ff1a;
    .status-cell-right {
      display: block;
    }
  }
}
// 负责人
::v-deep .leader-cell {
  cursor: pointer;
  display: flex;
  align-items: center;
  height: 100%;
  justify-content: space-between;
  padding: 0 10px;
  .leader-cell-right {
    width: 12px;
    height: 12px;
    fill: rgba(170, 170, 170, 1);
    display: none;
  }
  &:hover {
    background-color: #6698ff1a;
    .leader-cell-right {
      display: block;
    }
  }
}
// 开始结束时间
::v-deep .start-end-cell {
  padding: 0 10px;
  cursor: pointer;
  display: flex;
  align-items: center;
  height: 100%;
  justify-content: space-between;
  .start-end-cell-right {
    width: 12px;
    height: 12px;
    fill: rgba(170, 170, 170, 1);
    display: none;
  }
  &:hover {
    background-color: #6698ff1a;
    .start-end-cell-right {
      display: block;
    }
  }
}
// 任务进度
::v-deep .progress-cell {
  padding: 0 10px;
  display: flex;
  align-items: center;
  .progress-cell-bg {
    position: relative;
    width: 100%;
    height: 8px;
    background: #f5f7fa;
    border-radius: 4px;
    overflow: hidden;
    .progress-cell-value {
      position: absolute;
      left: 0;
      top: 0;
      transition: width 0.3s ease;
      height: 100%;
    }
  }
}
</style>
<style>
.no-padding-popover {
  padding: 0 !important;
}
</style>
